/*
 * Copyright (c) 1993-2003, Silicon Graphics, Inc.
 * All Rights Reserved
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose and without fee is hereby granted, provided that the above
 * copyright notice appear in all copies and that both the copyright
 * notice and this permission notice appear in supporting documentation,
 * and that the name of Silicon Graphics, Inc. not be used in
 * advertising or publicity pertaining to distribution of the software
 * without specific, written prior permission.
 *
 * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS" AND
 * WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
 * FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL SILICON
 * GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
 * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
 * OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION, LOSS OF
 * PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF THIRD
 * PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC.  HAS BEEN ADVISED OF
 * THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE POSSESSION, USE
 * OR PERFORMANCE OF THIS SOFTWARE.
 *
 * US Government Users Restricted Rights
 * Use, duplication, or disclosure by the Government is subject to
 * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
 * (c)(1)(ii) of the Rights in Technical Data and Computer Software
 * clause at DFARS 252.227-7013 and/or in similar or successor clauses
 * in the FAR or the DOD or NASA FAR Supplement.  Unpublished - rights
 * reserved under the copyright laws of the United States.
 *
 * Contractor/manufacturer is:
 *	Silicon Graphics, Inc.
 *	1500 Crittenden Lane
 *	Mountain View, CA  94043
 *	United State of America
 *
 * OpenGL(R) is a registered trademark of Silicon Graphics, Inc.
 */

/*
 *  cube.c
 *  This program demonstrates a single modeling transformation,
 *  glScalef() and a single viewing transformation, gluLookAt().
 *  A wireframe cube is rendered.
 */
#include <stdlib.h>
#include <windows.h>
#include <glut.h>
#include <stdio.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <cstdlib>
#include <vector>
#include <string>
#include <algorithm>
#include <fstream>
#include <cstdio>
#include <iostream>

GLfloat     rquad;                      // Angle For The Quad     ( NEW )
GLfloat     rquad1;
float angle = 0.0;

struct face
{
	int facenum;
	bool four;
	int faces[4];

	face(int facen, int f1, int f2, int f3) : facenum(facen)
	{
		faces[0]=f1;
		faces[1]=f2;
		faces[2]=f3;
		four=false;
	}

	face(int facen, int f1, int f2, int f3, int f4): facenum(facen)
	{
		faces[0]=f1;
		faces[1]=f2;
		faces[2]=f3;
		faces[3]=f4;
		four=true;
	}
};

struct coordinate
{
	float x, y, z;
	coordinate(float a, float b, float c) : x(a), y(b), z(c) {};
};


int loadObject(const char* filename)
{
	std::vector<std::string*> coord;
	std::vector<coordinate*> vertex;
	std::vector<face*> faces;
	std::vector<coordinate*> normals;
	std::ifstream in(filename);

	if(!in.is_open())
	{
		std::cout << "Not open" << std::endl;
		return -1;
	}


	char buf[256];
	while(!in.eof())
	{
		in.getline(buf, 256);
		coord.push_back(new  std::string(buf));
	}

	for(int i = 0; i < coord.size(); i++)
	{
		if((*coord[i])[0]=='#')
			continue;
		else if((*coord[i])[0] =='v' && (*coord[i])[1] == ' ' )
		{
			float tmpx, tmpy, tmpz;
			sscanf(coord[i]->c_str(), "v %f %f %f",&tmpx, &tmpy, &tmpz);
			vertex.push_back(new coordinate(tmpx, tmpy, tmpz));

		}
		else if((*coord[i])[0] =='v' && (*coord[i])[1] =='n' )
		{
			float tmpx, tmpy, tmpz;
			sscanf(coord[i]->c_str(), "vn %f %f %f",&tmpx, &tmpy, &tmpz);
			normals.push_back(new coordinate(tmpx, tmpy, tmpz));

		}else if((*coord[i])[0]=='f')
		{
			int a, b, c, d, e;

			if(count(coord[i]->begin(),coord[i]->end(),' ')==3)
			{
					sscanf(coord[i]->c_str(),"f %d//%d %d//%d %d//%d",&a,&b,&c,&b,&d,&b);
					faces.push_back(new face(b,a,c,d));
			}
			else
			{
					sscanf(coord[i]->c_str(),"f %d//%d %d//%d %d//%d %d//%d",&a,&b,&c,&b,&d,&b,&e,&b);
					faces.push_back(new face(b,a,c,d,e));
			}

		}

	}

	//zeichnen

	int num;
    num=glGenLists(1);
    glNewList(num,GL_COMPILE);
    for(int i=0;i<faces.size();i++)
    {
		if(faces[i]->four)
        {
			glBegin(GL_QUADS);
			glNormal3f(normals[faces[i]->facenum-1]->x,normals[faces[i]->facenum-1]->y,normals[faces[i]->facenum-1]->z);
            glVertex3f(vertex[faces[i]->faces[0]-1]->x,vertex[faces[i]->faces[0]-1]->y,vertex[faces[i]->faces[0]-1]->z);
            glVertex3f(vertex[faces[i]->faces[1]-1]->x,vertex[faces[i]->faces[1]-1]->y,vertex[faces[i]->faces[1]-1]->z);
            glVertex3f(vertex[faces[i]->faces[2]-1]->x,vertex[faces[i]->faces[2]-1]->y,vertex[faces[i]->faces[2]-1]->z);
            glVertex3f(vertex[faces[i]->faces[3]-1]->x,vertex[faces[i]->faces[3]-1]->y,vertex[faces[i]->faces[3]-1]->z);
            glEnd();
        }else
		{
			glBegin(GL_TRIANGLES);
            glNormal3f(normals[faces[i]->facenum-1]->x,normals[faces[i]->facenum-1]->y,normals[faces[i]->facenum-1]->z);
            glVertex3f(vertex[faces[i]->faces[0]-1]->x,vertex[faces[i]->faces[0]-1]->y,vertex[faces[i]->faces[0]-1]->z);
            glVertex3f(vertex[faces[i]->faces[1]-1]->x,vertex[faces[i]->faces[1]-1]->y,vertex[faces[i]->faces[1]-1]->z);
            glVertex3f(vertex[faces[i]->faces[2]-1]->x,vertex[faces[i]->faces[2]-1]->y,vertex[faces[i]->faces[2]-1]->z);
            glEnd();
        }
	}

	glEndList();

	for(int i=0; i<coord.size();i++)
		delete coord[i];

	for(int i=0; i<faces.size(); i++)
		delete faces[i];

	for(int i=0; i<normals.size();i++)
		delete normals[i];

	for(int i=0; i<vertex.size(); i++)
		delete vertex[i];

	return num;
}




int cube;


void init(void)
{
   glEnable(GL_DEPTH_TEST);							// Enables Depth Testing
   glShadeModel(GL_SMOOTH);							// Enable Smooth Shading
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   gluPerspective(45,640.0/480.0,1.0,500.0);
   glMatrixMode(GL_MODELVIEW);
   cube=loadObject("link.obj");

   //Spot
   GLfloat ambient[] = { 1.0, 1.0, 1.0, 1.0 };
   GLfloat diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
   GLfloat specular[] = { 1.0, 1.0, 1.0, 1.0 };
   GLfloat position[] = { 1.0, 0.0, 0.0, 0.0 };

   glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
   glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
   glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
   glLightfv(GL_LIGHT0, GL_POSITION, position);

   float LightDir[3] = {-5.0f, 0.0f, 0.0f};
   glLighti(GL_LIGHT0, GL_SPOT_CUTOFF, 10);
   glLightfv(GL_LIGHT0, GL_POSITION, position);
   glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, LightDir);


   //gerichtetes
   GLfloat ambient1[] = { 1.0, 0.0, 0.0, 1.0 };
   GLfloat diffuse1[] = { 1.0, 0.0, 0.0, 1.0 };
   GLfloat specular1[] = { 1.0, 1.0, 1.0, 1.0 };
   GLfloat position1[] = { 5.0, 10.0, 0.0, 0.0 };

   glLightfv(GL_LIGHT1, GL_AMBIENT, ambient1);
   glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse1);
   glLightfv(GL_LIGHT1, GL_SPECULAR, specular1);
   glLightfv(GL_LIGHT1, GL_POSITION, position1);

   glEnable(GL_LIGHTING);
   glEnable(GL_LIGHT0);
   glEnable(GL_LIGHT1);

   //
   GLfloat ambient2[] = { 0.0, 1.0, 0.0, 1.0 };
   GLfloat diffuse2[] = { 0.0, 1.0, 0.0, 1.0 };
   GLfloat specular2[] = { 1.0, 1.0, 1.0, 1.0 };
   GLfloat position2[] = { 5.0, 0.0, 0.0, 0.0 };

   glLightfv(GL_LIGHT2, GL_AMBIENT, ambient2);
   glLightfv(GL_LIGHT2, GL_DIFFUSE, diffuse2);
   glLightfv(GL_LIGHT2, GL_SPECULAR, specular2);
   glLightfv(GL_LIGHT2, GL_POSITION, position2);


   glEnable(GL_LIGHT2);





}


void LudvigsenNeleDisplay(void)
{
   int i= 0;
//   while (i < 500)
   {
	   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	   glLoadIdentity ();             /* clear the matrix */
	   // viewing transformation
	   // Look from 0.0, 0.0, 5.0 to 0.0, 0.0, 0.0 where up is 0.0, 1.0, 0.0
	   gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

	   // Bitte ab hier die NeHe-Tutorials einarbeiten
	   glRotatef(rquad,0.0f,1.0f,0.0f);            // Rotate The Quad On The Y axis ( NEW )
	   glScalef(1.0f,2.0f,1.0f);
	   glColor3f(0.0f,1.0f,0.0f);
	   glutSolidCube(1.0f);
	   glEnd();

	   glLoadIdentity ();             /* clear the matrix */
	   gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
	   glRotatef(rquad,0.0f,1.0f,0.0f);
	   glTranslatef(0.0f, 1.0f, 0.0f);
	   glRotatef(60.0, 0.0f, 0.0f, 1.0f);
	   glTranslatef(0.0f, 1.0f, 0.0f);
	   glScalef(1.0f,2.0f,1.0f);
	   glColor3f(0.0f,1.0f,0.0f);
	   glutSolidCube(1.0f);
	   glEnd();

	   glLoadIdentity ();             /* clear the matrix */
	   gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
	   glRotatef(120.0+rquad,0.0f,1.0f,0.0f);
	   glTranslatef(0.0f, 1.0f, 0.0f);
	   glRotatef(60.0, 0.0f, 0.0f, 1.0f);
	   glTranslatef(0.0f, 1.0f, 0.0f);
	   glScalef(1.0f,2.0f,1.0f);
	   glColor3f(0.0f,1.0f,0.0f);
	   glutSolidCube(1.0f);
	   glEnd();

	   glLoadIdentity ();             /* clear the matrix */
	   gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
	   glRotatef(-120.0+rquad,0.0f,1.0f,0.0f);
	   glTranslatef(0.0f, 1.0f, 0.0f);
	   glRotatef(60.0, 0.0f, 0.0f, 1.0f);
	   glTranslatef(0.0f, 1.0f, 0.0f);
	   glScalef(1.0f,2.0f,1.0f);
	   glColor3f(0.0f,1.0f,0.0f);
	   glutSolidCube(1.0f);
	   glEnd();

	   rquad-=0.02f;                       // Decrease The Rotation Variable For The Quad     ( NEW )

	   // Bitte bis hier die NeHe-Tutorials einarbeiten

	   glLoadIdentity();
       glTranslatef(3.0,-3.0,-5.0);
       glRotatef(angle,0.0,1.0,0.0);
       glCallList(cube);
	   glFlush ();
   }
}


void reshape (int w, int h)
{
   glViewport (0, 0, (GLsizei) w, (GLsizei) h);
   glMatrixMode (GL_PROJECTION);
   glLoadIdentity ();
   glFrustum (-1.0, 1.0, -1.0, 1.0, 1.5, 20.0);
   glMatrixMode (GL_MODELVIEW);
}

void keyboard(unsigned char key, int x, int y)
{
   switch (key) {
      case 27:
         exit(0);
         break;
   }
}

void idle( void )
{
glutPostRedisplay();
}

int main(int argc, char** argv)
{
   glutInit(&argc, argv);
   glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB );
   glutInitWindowSize (500, 500);
   glutInitWindowPosition (100, 100);
   glutCreateWindow (argv[0]);
   init ();
   glutIdleFunc( idle );
   glutDisplayFunc(LudvigsenNeleDisplay);
   glutReshapeFunc(reshape);
   glutKeyboardFunc(keyboard);
   glutMainLoop();
   return 0;
}


